package computepi

import (
	"fmt"
	"strconv"
)

type Pi struct {
	digits int
}

func NewPiDefault() *Pi {
	return &Pi{
		digits: 1000,
	}
}

func NewPiDigits(digits int) *Pi {
	return &Pi{
		digits: digits,
	}
}

// Spigot 算法计算圆周率
func (p *Pi) Spigot() string {
	if p.digits <= 0 {
		return "3."
	}
	decimals := int64(p.digits + 1)
	n := int64(decimals * 14 / 4)   // 计算到公式的第多少项
	remainder := make([]int64, n+1) // 建立的这个数组，只用来保存每一项每一轮计算之后的余数
	lowBits := int64(0)

	// 将数组全部初始化为 2000
	for i := int64(0); i <= n; i++ {
		remainder[i] = 2000
	}
	pi := ""
	// 开始外层循环，每循环一次，级数少计算 14 项，输出 4 位 pi 值
	for n > 0 {
		denominator := 2*n - 1
		quotient := int64(0)
		sum := int64(0)

		sum += remainder[n] * 10000
		remainder[n] = sum % denominator
		quotient = sum / denominator

		// 开启内层循环，该循环从 b == n-1 开始，循环到 b == 0
		b := n - 1
		for b > 0 {
			sum = quotient*int64(b) + remainder[b]*10000

			denominator = 2*b - 1

			// 余数保存到数组中，进入下一轮大循环，商进入下一轮小循环
			remainder[b] = sum % denominator
			quotient = sum / denominator

			b--
		}

		n -= 14
		// 输出高 4 位，低 4 位进入下一轮循环
		// fmt.Printf("%04d", lowBits+sum/10000)
		lowBitsStr := fmt.Sprintf("%04d", lowBits+sum/10000)
		pi += lowBitsStr
		lowBits = sum % 10000
	}
	return pi[:1] + "." + pi[1:p.digits+1]
}

// 将圆周率转换成二进制字符串。
func (p *Pi) PiBinary() string {
	pi := p.Spigot()
	binaryStr := ""
	for _, v := range pi {
		binaryStr += strconv.FormatInt(int64(v), 2)
	}
	return binaryStr
}
